package com.doublecheck.project.client;

import java.util.ArrayList;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.editor.client.Editor.Path;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.chart.client.chart.Chart;
import com.sencha.gxt.chart.client.chart.Legend;
import com.sencha.gxt.chart.client.chart.axis.CategoryAxis;
import com.sencha.gxt.chart.client.chart.axis.NumericAxis;
import com.sencha.gxt.chart.client.chart.event.AxisSelectionEvent;
import com.sencha.gxt.chart.client.chart.event.AxisSelectionEvent.AxisSelectionHandler;
import com.sencha.gxt.chart.client.chart.event.SeriesSelectionEvent;
import com.sencha.gxt.chart.client.chart.event.SeriesSelectionEvent.SeriesSelectionHandler;
import com.sencha.gxt.chart.client.chart.series.BarSeries;
import com.sencha.gxt.chart.client.chart.series.SeriesLabelProvider;
import com.sencha.gxt.chart.client.chart.series.SeriesToolTipConfig;
import com.sencha.gxt.chart.client.draw.RGB;
import com.sencha.gxt.chart.client.draw.sprite.TextSprite;
import com.sencha.gxt.core.client.ValueProvider;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.ModelKeyProvider;
import com.sencha.gxt.data.shared.PropertyAccess;
import com.sencha.gxt.fx.client.Draggable;
import com.sencha.gxt.widget.core.client.ContentPanel;
import com.sencha.gxt.widget.core.client.Resizable;
import com.sencha.gxt.widget.core.client.Resizable.Dir;
import com.sencha.gxt.widget.core.client.TabItemConfig;
import com.sencha.gxt.widget.core.client.TabPanel;
import com.sencha.gxt.widget.core.client.Window;
import com.sencha.gxt.widget.core.client.box.MessageBox;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData;
import com.sencha.gxt.widget.core.client.event.ExpandEvent;
import com.sencha.gxt.widget.core.client.event.ExpandEvent.ExpandHandler;
import com.sencha.gxt.widget.core.client.event.HideEvent;
import com.sencha.gxt.widget.core.client.event.HideEvent.HideHandler;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent.SelectHandler;
import com.sencha.gxt.widget.core.client.info.Info;
import com.sencha.gxt.widget.core.client.toolbar.ToolBar;

public class BarChart extends Chart<Item> {
	/*
	 * Metadata for Bar Chart
	 */
	private int numOfSeries;
	private ArrayList<Item> data;
	private String chartTitle;
	private String X_axis;
	private String Y_axis;
	private AxisType X_type;
	private AxisType Y_type;

	/*
	 * Variables for Tab Panel
	 */
	private Window window;
	private TabPanel tabPanel;
	private ContentPanel panel;	
	
	/*
	 * constructor
	 */
	public BarChart(int numOfSeries, BarChart_Dataset dataset, String title,
			String X_axis, AxisType X_type, String Y_axis, AxisType Y_type) {
		this.numOfSeries = numOfSeries;
		this.data = dataset.getDataset();
		this.chartTitle = title;
		this.X_axis = X_axis;
		this.X_type = X_type;
		this.Y_axis = Y_axis;
		this.Y_type = Y_type;
	}
	public BarChart() {}

	/*
	 * Access to Data Object
	 */
	public interface DataPropertyAccess extends PropertyAccess<Item> {
		ValueProvider<Item, Double> value0();
		ValueProvider<Item, Double> value1();
		ValueProvider<Item, Double> value2();
		ValueProvider<Item, Double> value3();
		ValueProvider<Item, Double> value4();		
		ValueProvider<Item, String> category();

		@Path("category")
		ModelKeyProvider<Item> categoryKey();
	}

	private static final DataPropertyAccess dataAccess = GWT.create(DataPropertyAccess.class);

	@Override
	public Widget asWidget() {		
		VerticalLayoutContainer tpLayout = new VerticalLayoutContainer();
		tpLayout = null;
		tpLayout = initiateChart(numOfSeries, data, chartTitle, X_axis, X_type, Y_axis, Y_type);

		//For tab panel
		tabPanel = new TabPanel();
		tabPanel.setTitle(chartTitle);
		tabPanel.setCloseContextMenu(true);	
		tabPanel.setTabScroll(true);
		tabPanel.setBorders(false);
		tabPanel.add(tpLayout, new TabItemConfig(chartTitle, false));
		tabPanel.setLayoutData(new VerticalLayoutData(1, 1));		
		//For main panel containing tabPanel
		panel = new ContentPanel();
		panel.getElement().getStyle().setMargin(10, Unit.PX);
		panel.setCollapsible(true);
		panel.setHeadingText("Bar Chart");
		panel.setPixelSize(400, 320);
		panel.setBodyBorder(true);
		new Draggable(panel, panel.getHeader()).setUseProxy(false);
		final Resizable resizePanel = new Resizable(panel, Dir.E, Dir.SE, Dir.S);
		resizePanel.setMinHeight(400);
		resizePanel.setMinWidth(400);

		panel.addExpandHandler(new ExpandHandler() {
			@Override
			public void onExpand(ExpandEvent event) {
				resizePanel.setEnabled(true);
			}
		});
		initiateWindow();
		
		return panel;
	}		
	
	/*For zoom-in event of the chart*/
	public void initiateWindow(){		
		final VerticalLayoutContainer panelLayout = new VerticalLayoutContainer();
		final ToolBar toolBar = new ToolBar();
		window = new Window();
	    window.setPixelSize(900, 700);
	    window.setModal(true);
	    window.setBlinkModal(true);	    
	    window.setHeadingText("Bar Chart");
	    window.addHideHandler(new HideHandler() {
	        @Override
	        public void onHide(HideEvent event) {
	            TextButton open = ((Window) event.getSource()).getData("open");
	            open.focus();	          
	            panelLayout.clear();
				panelLayout.add(toolBar);
				panelLayout.add(tabPanel);
				panel.add(panelLayout);
	        }
	    });
	    /*Close button at the bottom of window*/
		TextButton closeBtn = new TextButton("Close");
		closeBtn.addSelectHandler(new SelectHandler() {
			@Override
			public void onSelect(SelectEvent event) {
				panelLayout.clear();
				panelLayout.add(toolBar);
				panelLayout.add(tabPanel);
				panel.add(panelLayout);
				window.hide();
			}
		});
		window.addButton(closeBtn);
		window.setFocusWidget(window.getButtonBar().getWidget(0));		
	    /*zoom-in button on toolbar*/	    
	    TextButton openBtn = new TextButton("Zoom In");
	    openBtn.addSelectHandler(new SelectHandler() {
	    	@Override
	    	public void onSelect(SelectEvent event) {
	    		window.add(tabPanel);
	    		window.show();
	    	}
	    });
	    window.setData("open", openBtn);	    	    
	    toolBar.add(openBtn);
	    toolBar.setLayoutData(new VerticalLayoutData(1, -1));
	    
	    panelLayout.add(toolBar);
		panelLayout.add(tabPanel);
		panel.add(panelLayout);
	}
	
	public VerticalLayoutContainer initiateChart(final int NewNumOfSeries, final ArrayList<Item> newData, final String chartTitle,
			final String X_axis, final AxisType X_type, final String Y_axis, final AxisType Y_type){
		
		/*Local variables*/
		final ListStore<Item> store = new ListStore<Item>(dataAccess.categoryKey());
		final Chart<Item> chart = new Chart<Item>();
		NumericAxis<Item> axis = new NumericAxis<Item>();
		CategoryAxis<Item, String> catAxis = new CategoryAxis<Item, String>();
		BarSeries<Item> bar = new BarSeries<Item>();
		Legend<Item> legend = new Legend<Item>();		
		/*Assign dataset to store*/	
		store.addAll(newData);
		/*Setting configuration for chart*/
		chart.setTitle(chartTitle);
		chart.setStore(store);
		chart.setShadow(true);
		
		/* Initiate X and Y */
		if ((X_type == AxisType.NumericAxis) && (Y_type == AxisType.CategoryAxis)) {			
			axis.setPosition(Position.BOTTOM);
			if (NewNumOfSeries >= 1)
				axis.addField(dataAccess.value0());
			if (NewNumOfSeries >= 2)
				axis.addField(dataAccess.value1());
			if (NewNumOfSeries >= 3)
				axis.addField(dataAccess.value2());
			if (NewNumOfSeries >= 4)
				axis.addField(dataAccess.value3());
			if (NewNumOfSeries == 5)
				axis.addField(dataAccess.value4());

			TextSprite title = new TextSprite(X_axis);
			title.setFontSize(18);
			axis.setTitleConfig(title);
			axis.setDisplayGrid(true);
			axis.setMinimum(0);
			axis.setMaximum(100);
			chart.addAxis(axis);
			
			catAxis.setPosition(Position.LEFT);
			catAxis.setField(dataAccess.category());
			title = new TextSprite(Y_axis);
			title.setFontSize(18);
			catAxis.setTitleConfig(title);
			chart.addAxis(catAxis);

			/* Define one data series for bar chart */
			bar.setYAxisPosition(Position.BOTTOM);
			if (NewNumOfSeries >= 1)
				bar.addYField(dataAccess.value0());
			if (NewNumOfSeries >= 2)
				bar.addYField(dataAccess.value1());
			if (NewNumOfSeries >= 3)
				bar.addYField(dataAccess.value2());
			if (NewNumOfSeries >= 4)
				bar.addYField(dataAccess.value3());
			if (NewNumOfSeries == 5)
				bar.addYField(dataAccess.value4());
			
			bar.addColor(new RGB(2, 93, 140));		// blue			
			bar.addColor(new RGB(255, 204, 0));		// yellow		
			bar.addColor(new RGB(255, 0, 51));		// red			
			bar.addColor(new RGB(127, 178, 27));	// green			
			bar.addColor(new RGB(153, 153, 153));  	// gray
			bar.setHighlighting(true);
			chart.addSeries(bar);

		} else if ((X_type == AxisType.CategoryAxis) && (Y_type == AxisType.NumericAxis)) {			
			axis.setPosition(Position.LEFT);
			if (NewNumOfSeries >= 1)
				axis.addField(dataAccess.value0());
			if (NewNumOfSeries >= 2)
				axis.addField(dataAccess.value1());
			if (NewNumOfSeries >= 3)
				axis.addField(dataAccess.value2());
			if (NewNumOfSeries >= 4)
				axis.addField(dataAccess.value3());
			if (NewNumOfSeries == 5)
				axis.addField(dataAccess.value4());

			TextSprite title = new TextSprite(Y_axis);
			title.setFontSize(18);
			axis.setTitleConfig(title);
			axis.setDisplayGrid(true);
			axis.setMinimum(0);
			axis.setMaximum(100);
			chart.addAxis(axis);

			catAxis.setPosition(Position.BOTTOM);
			catAxis.setField(dataAccess.category());
			title = new TextSprite(X_axis);
			title.setFontSize(18);
			catAxis.setTitleConfig(title);
			chart.addAxis(catAxis);

			/* Define one data series for bar chart */
			bar.setYAxisPosition(Position.LEFT);
			if (numOfSeries >= 1)
				bar.addYField(dataAccess.value0());
			if (numOfSeries >= 2)
				bar.addYField(dataAccess.value1());
			if (numOfSeries >= 3)
				bar.addYField(dataAccess.value2());
			if (numOfSeries >= 4)
				bar.addYField(dataAccess.value3());
			if (numOfSeries == 5)
				bar.addYField(dataAccess.value4());

			bar.addColor(new RGB(2, 93, 140));		// blue			
			bar.addColor(new RGB(255, 204, 0));		// yellow		
			bar.addColor(new RGB(255, 0, 51));		// red			
			bar.addColor(new RGB(127, 178, 27));	// green			
			bar.addColor(new RGB(153, 153, 153));  	// gray
			bar.setColumn(true);
			bar.setHighlighting(true);

			chart.addSeries(bar);

		} else {Info.display("Error", "Wrong parameters provided!");}
		
		/*Category selection handler for zoom-in event*/
		catAxis.addAxisSelectionHandler(new AxisSelectionHandler(){
			@Override
			public void onAxisSelection(AxisSelectionEvent event) {
				if(newData.size()>=2){
					int index = event.getIndex();
					ArrayList<Item> drillDownData = new ArrayList<Item>();				
					drillDownData.add(newData.get(index));
					VerticalLayoutContainer newLayout = new VerticalLayoutContainer();		
					newData.add(store.get(index));				
					newLayout = initiateChart(NewNumOfSeries, drillDownData, chartTitle, X_axis, X_type, Y_axis, Y_type);				
					
					tabPanel.add(newLayout, new TabItemConfig(chartTitle + "-" + event.getValue(), true));
					tabPanel.setActiveWidget(tabPanel.getWidget(tabPanel.getWidgetCount()- 1));
				}
				else{
					Info.display("Alert", "Data can't be drilled down!");
				}
			}					
		});		

		/* Set legend */		
		legend.setPosition(Position.RIGHT);
		legend.setItemHighlighting(true);
		legend.setItemHiding(true);
		legend.setChart(chart);
		chart.setLegend(legend);		
		
		/* Series selection handler */
		bar.addSeriesSelectionHandler(new SeriesSelectionHandler<Item>() {
			@Override
			public void onSeriesSelection(SeriesSelectionEvent<Item> event) {
				/* Fire corresponding action along with series selection */
				MessageBox pop = new MessageBox("Alert", event.getItem().getCategory()
						+ ":"
						+ String.valueOf(event.getItem().getValue0()));				
				RootPanel.get().add(pop);
				pop.show();
			}
		});
				
		/*Mouse over event for sprites*/
		SeriesToolTipConfig<Item> tooltip = new SeriesToolTipConfig<Item>();
	    tooltip.setLabelProvider(new SeriesLabelProvider<Item>() {
	    	@Override
	        public String getLabel(Item item, ValueProvider<? super Item, ? extends Number> valueProvider) {
	    		String output = dataAccess.category().getValue(item) + ":" + String.valueOf(valueProvider.getValue(item));
	    		return output;
	    	}
	    });
	    
	    tooltip.setDismissDelay(2000);
	    bar.setToolTipConfig(tooltip);
		VerticalLayoutContainer layout = new VerticalLayoutContainer();					
		chart.setLayoutData(new VerticalLayoutData(1, 1));
		layout.add(chart.asWidget());		
		
		return layout;		
	}	
}
